package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.constants.message.WmNewsMessageConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.media.dtos.NewsAuthDto;
import com.heima.model.media.dtos.WmNewsDto;
import com.heima.model.media.dtos.WmNewsPageReqDto;
import com.heima.model.media.pojos.WmMaterial;
import com.heima.model.media.pojos.WmNews;
import com.heima.model.media.pojos.WmNewsMaterial;
import com.heima.model.media.pojos.WmUser;
import com.heima.model.media.vos.WmNewsVo;
import com.heima.utils.threadlocal.WmThreadLocalUtils;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${file.oss.web-site}")
    private String webSite;

    @Autowired
    WmMaterialMapper wmMaterialMapper;

    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    KafkaTemplate kafkaTemplate;

    @Autowired
    WmNewsMapper wmNewsMapper;
    @Autowired
    WmUserMapper wmUserMapper;

    /**
     * 查询文章列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        //检查参数
        if (dto == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        dto.checkParam();
        LambdaQueryWrapper<WmNews> queryWrapper = Wrappers.<WmNews>lambdaQuery();
        //检查是否登录
        WmUser user = WmThreadLocalUtils.getUser();
        if (user == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        queryWrapper.eq(WmNews::getUserId, user.getId());
        //判断是否有状态信息
        if (dto.getStatus() != null) {
            queryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        //判断是否有输入关键字
        if (dto.getKeyword() != null) {
            queryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        //判断是否输入频道
        if (dto.getChannelId() != null) {
            queryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        //判断是否有发布日期
        if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            queryWrapper.between(WmNews::getCreatedTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }
        //按照日期排序
        queryWrapper.orderByDesc(WmNews::getCreatedTime);
        //封装查询条件
        Page<WmNews> wmNewsPage = new Page<>(dto.getPage(), dto.getSize());
        IPage<WmNews> page = page(wmNewsPage, queryWrapper);
        PageResponseResult pageResponseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
//        for (WmNews wmNews : page.getRecords()) {
//            wmNews.setImages(webSite+wmNews.getImages());
//        }
        pageResponseResult.setData(page.getRecords());
        pageResponseResult.setHost(webSite);
        //返回参数
        return pageResponseResult;
    }

    /**
     * 保存或者修改文章方法
     *
     * @param wmNewsDto
     * @param isSubmit  是否为提交 1 为提交 0为草稿
     * @return
     */
    @Transactional
    @Override
    public ResponseResult submitNews(WmNewsDto wmNewsDto, Short isSubmit) {
        //检查参数
        if (wmNewsDto == null || (isSubmit != 0 && isSubmit != 1)) {
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //判断用户是否登录
        if (WmThreadLocalUtils.getUser() == null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //判断内容中图片信息是否存在
        if (StringUtils.isBlank(wmNewsDto.getContent())) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "缺少文章数据");
        }
        //获取文章中图片的集合
        List<String> images = getImagesFromContent(wmNewsDto.getContent());

        //判断文章中是否存在图片
        List<Integer> imageIds = new ArrayList<>();
        if (images != null && !images.isEmpty()) {
            //获取素材图片id集合
            imageIds = getImageIds(images);
        }
        //判断封面模式
        return doSubmitNews(wmNewsDto, isSubmit, imageIds,images);
    }

    /**
     * 根据id查询文章
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsById(Integer id) {
        //检查参数
        if(id==null){
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = getById(id);
        if(wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        ResponseResult responseResult = ResponseResult.okResult(wmNews);
        responseResult.setHost(webSite);
        return responseResult;
    }

    /**
     * 根据文章id删除文章方法
     * @param id
     * @return
     */
    @Override
    public ResponseResult delNews(Integer id) {
        //检查参数
        if(id==null){
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //根据id获取文章
        WmNews wmNews = getById(id);
        if(wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章数据不存在");
        }
        //判断文章状态是否是已上架，enable为1
        if(wmNews.getEnable()==1&&wmNews.getStatus()==9){
            CustException.cust(AppHttpCodeEnum.FILE_DELETE_ERROR,"请先下架再删除");
        }
        //删除中间表中数据
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id));
        //删除文章表中的数据
        removeById(id);
        return ResponseResult.okResult();
    }

    /**
     * 自媒体文章的上架，下架
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //检查参数
        if(dto==null||dto.getId()==null){
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //判断是否 登录
        if(WmThreadLocalUtils.getUser()==null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        //根据id获取文章
        WmNews wmNews = getById(dto.getId());
        if(wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章数据不存在");
        }
        //判断文章状态是否是发布状态
        if(wmNews.getStatus()!=9){
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"当前文章未发布不能下架");
        }

        //封装更新参数
        update(Wrappers.<WmNews>lambdaUpdate().set(WmNews::getEnable,dto.getEnable())
                .eq(WmNews::getId,dto.getId())
        .eq(WmNews::getUserId,WmThreadLocalUtils.getUser().getId()));
        //1.检查参数
        //2.查询文章
        //3.判断文章是否发布
        //4.修改文章状态，同步到app端（后期做）TODO
        // ***发消息
        if(wmNews.getArticleId()!=null){
            Map<String,Object> mesMap = new HashMap<>();
            mesMap.put("enable",dto.getEnable());
            mesMap.put("articleId",wmNews.getArticleId());
            kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC,JSON.toJSONString(mesMap));
        }
        //封装响应返回
        return ResponseResult.okResult();
    }

    /**
     * 查询需要发布的文章id集合
     * @return
     */
    @Override
    public List<Integer> findRelease() {
        //封装查询条件，状态为人工审核通过和自动审核通过且发布时间小于当前时间的
        List<WmNews> list = list(Wrappers.<WmNews>lambdaQuery().in(WmNews::getStatus, 4, 8)
                .le(WmNews::getPublishTime,new Date()));
        if(list!=null&&!list.isEmpty()){
            List<Integer> idList = list.stream().map(WmNews::getId)
                    .collect(Collectors.toList());
            return idList;
        }
        return null;
    }

    /**
     * 查询文章列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(NewsAuthDto dto) {
        //检查参数
        dto.checkParam();
        //title拼接模糊查询参数
        if(StringUtils.isNotBlank(dto.getTitle())){
            dto.setTitle("%"+dto.getTitle()+"%");
        }
        //获取当前页
        Integer current = dto.getPage();
        //设置分页查询偏移量
        dto.setPage((current-1)*dto.getSize());
        //查询文章列表
        List<WmNewsVo> wmNewsVoList = wmNewsMapper.findListAndPage(dto);
        long toal = wmNewsMapper.findListCount(dto);
        //封装返回参数
        PageResponseResult pageResponseResult = new PageResponseResult(current, dto.getSize(), (int)toal);
        pageResponseResult.setData(wmNewsVoList);
        return pageResponseResult;
    }

    /**
     * 查询文章详情
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        //检查参数
        if(id==null){
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //查询文章信息
        WmNews wmNews = getById(id);
        if(wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章信息不存在");
        }
        //查询作者姓名
        Integer userId = wmNews.getUserId();
        if(userId==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章作者信息不存在");
        }
        //查询文章作者信息
        WmUser wmUser = wmUserMapper.selectById(userId);
        if(wmUser==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章作者信息查询不到");
        }
        //封装返回参数
        WmNewsVo wmNewsVo = new WmNewsVo();
        BeanUtils.copyProperties(wmNews,wmNewsVo);
        wmNewsVo.setAuthorName(wmUser.getName());
        ResponseResult responseResult = ResponseResult.okResult(wmNewsVo);
        responseResult.setHost(webSite);
        return responseResult;
    }

    @Override
    public ResponseResult updateStatus(Short status, NewsAuthDto dto) {
        //检查参数
        if(dto==null){
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //根据传入参数修改文章
        WmNews wmNews = getById(dto.getId());
        if(wmNews==null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //修改文章状态
        if(dto.getMsg()!=null){
            wmNews.setReason(dto.getMsg());
        }
        wmNews.setStatus(status);
        updateById(wmNews);
        return ResponseResult.okResult();
    }

    /**
     * 获取文章内容里图片url集合方法
     * @param content
     * @return
     */
    private List<String> getImagesFromContent(String content) {
        List<Map> lists = JSONArray.parseArray(content, Map.class);
        if(lists==null||lists.isEmpty()){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        List<String> images = lists.stream().filter(map -> map.get("type").equals(WemediaConstants.WM_NEWS_TYPE_IMAGE))
                .map(url -> url.get("value").toString())
                .map(imageMap -> imageMap.replace(webSite, ""))
                .collect(Collectors.toList());
        return images;
    }

    /**
     * 符合条件执行方法
     *
     * @param wmNewsDto
     * @param isSubmit
     * @return
     */
    private ResponseResult doSubmitNews(WmNewsDto wmNewsDto, Short isSubmit, List<Integer> imageIds,List<String> coverImages) {
        //封装文章数据
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(wmNewsDto, wmNews);
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1);
        wmNews.setStatus(isSubmit);

        //封面类型不为无图类型
        List<Integer> coverImageIds = null;
        if (wmNews.getType() != 0) {
            //判断提交类型
            if (wmNews.getType() == -1) {
                //封面模式为自动，为封面赋值
                setCoverImages(coverImages,wmNewsDto);
                wmNews.setType(null);
            }
            //获取封面图片字符串
            String images = createImages(wmNewsDto.getImages());
            List<String> imagesList = Arrays.asList(images.split(","));
            //获取封面的素材图片id集合
            coverImageIds = getImageIds(imagesList);
            wmNews.setImages(images);
        }
        //添加或者更新文章数据
        saveOrUpdateWmNews(wmNews, imageIds, coverImageIds);
        // 4 发消息给admin审核文章
        Map map = new HashMap();
        map.put("wmNewsId", wmNews.getId());
        kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, JSON.toJSONString(map));
        return ResponseResult.okResult();
    }

    /**
     * 为自动类型设置封面
     * @param coverImages
     */
    private void setCoverImages(List<String> coverImages,WmNewsDto wmNewsDto) {
        //判断素材图片集合长度
        int size = coverImages.size();
        List<String> list = new ArrayList<>();
        //根据文章中图片数量设置封面图片
        if(size==0){
            wmNewsDto.setImages(null);
        }
        if(size<=2){
            list.add(coverImages.get(0));
            wmNewsDto.setImages(list);
        }
        if(size>2){
            list.add(coverImages.get(0));
            list.add(coverImages.get(1));
            list.add(coverImages.get(2));
            wmNewsDto.setImages(list);
        }
    }

    /**
     * 创建封面图片数据方法
     *
     * @param images
     * @return
     */
    private String createImages(List<String> images) {
        if (images == null || images.isEmpty()) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "封面图片数据不存在");
        }
        return images.stream().map(url -> url.replace(webSite, ""))
                .collect(Collectors.joining(","));
    }

    /**
     * 添加或者更新文章方法
     *
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews, List<Integer> imageIds, List<Integer> coverImageIds) {
        //判断是新增还是修改方法
        if (wmNews.getId() == null) {
            wmNews.setCreatedTime(new Date());
        } else {
            //修改先删除中间表中数据
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId, wmNews.getId()));
        }
        saveOrUpdate(wmNews);
        //文章中素材图片id不为空则插入
        if(imageIds!=null&&!imageIds.isEmpty()){
            wmNewsMaterialMapper.saveRelations(imageIds, wmNews.getId(), WemediaConstants.WM_CONTENT_REFERENCE);
        }
        //判断封面图片id集合不为空则插入
        if (coverImageIds != null && !coverImageIds.isEmpty()) {
            wmNewsMaterialMapper.saveRelations(coverImageIds, wmNews.getId(), WemediaConstants.WM_IMAGE_REFERENCE);
        }
    }

    /**
     * 根据图片url集合获取素材图片ID集合的方法
     *
     * @param images
     * @return
     */
    private List<Integer> getImageIds(List<String> images) {
        List<Integer> imageIds = new ArrayList<>();
        for (String image : images) {
            WmMaterial wmMaterial = wmMaterialMapper.selectOne(Wrappers.<WmMaterial>lambdaQuery().eq(WmMaterial::getUrl, image));
            if (wmMaterial == null) {
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "素材图片不存在");
            }
            imageIds.add(wmMaterial.getId());
        }
        return imageIds;
    }
}
